	/**
	 * Le but de cette classe est :
	 * - de pouvoir renvoyer la liste de produits commandés pour la réservation (méthode 'trans_listCommand')
	 * - de pouvoir renvoyer la date de livraison et le coût après chaque insertion d'un nouveau produit (méthode 'calculDelai_Cout')
	 * (cela émet une réservation d'office)
	 * - de pouvoir valider une réservation
	 */
package com.central;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;


import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class aaCentral implements ICentral
{	
	private Socket skt;
	private BufferedReader in;
	private PrintWriter out;
	
	private String ipAtt0;
	private Integer portAtt0;
	private String ipAtt1;
	private Integer portAtt1;
	private String ipAtt2;
	private Integer portAtt2;
	private String ipAtt3;
	private Integer portAtt3;
	private String ipAtt4;
	private Integer portAtt4;
	private  Hashtable<Integer, Integer[]> prdtsCommandes = new Hashtable<Integer, Integer[]>();
	
	public aaCentral(int idProd, int quantity,int codeLivraison, int pu)
	{
		System.out.println("########### ( 46 ) Central instanciation");
		try {			
			configConnexion();
			JSONObject resDelaiCout = null;
			JSONObject resCommande = null;
			
			//Traitement		
			resDelaiCout = calculDelai_Cout(codeLivraison, idProd, quantity, pu);
			//resCommande = trans_listCommand(prdtsCommandes);
			
			//Renvoi du délai et du coût
			//Quit
			quit();
		}catch(Exception e){ 
			System.out.print("WAOUH !!! Hey looser : you failed !\n");   
		}
	}

	public aaCentral() {
		// TODO Auto-generated constructor stub
	}

	private void configConnexion() throws UnknownHostException 
	{
		System.out.println("########### ( 70 ) Central configConnexion");
		//Setting des adresses IP et des ports
		ipAtt0 = "127.0.0.1";
		ipAtt1 = "127.0.0.1";
		ipAtt2 = "127.0.0.1";
		ipAtt3 = "127.0.0.1";
		ipAtt4 = "127.0.0.1";
		
		portAtt0 = 10001;
		portAtt1 = 10002;
		portAtt2 = 10003;
		portAtt3 = 10004;
		portAtt4 = 10005;
	}
	
	/**
	 * Fonction de calcul du délai et du coût
	 * Résultat attendu :
	 * JSONObject [] composé de la date de livraison et du coût
	 */
	public JSONObject calculDelai_Cout (Integer codeLivraison, Integer Id, Integer qte, Integer prixUnit) throws UnknownHostException, IOException, JSONException
	{
		System.out.println("########### ( 92 ) Central calculDelais_Cout");
		JSONObject jsoRes = new JSONObject();
		
		//Calcul des délais produit par produit
		Integer numServerLoc = codeLivraison-10001;
		Integer resInterPrdt[] = new Integer[7];
				
		//Traitement de l'interrogation par produit
		resInterPrdt = interParProduit(Id, qte, numServerLoc);
		resInterPrdt[6] = prixUnit*qte;
		
		//Stockage dans la table finale
		if(!prdtsCommandes.containsKey(Id)){
			prdtsCommandes.put(Id, resInterPrdt);
		}
		else{
			prdtsCommandes.remove(Id);
			prdtsCommandes.put(Id, resInterPrdt);
		}
		
		//Calcul de la date de livraison et du coût de la commande
		Date dateLivraison = new Date();
		Integer maxDelai = 0;
		Integer coutTotal = 0;

		if(prdtsCommandes.size()!=0){
			Enumeration<Integer> enu = prdtsCommandes.keys();
			Integer[] n = new Integer[7];
			Integer i = 0;
			while(enu.hasMoreElements()){
				n = prdtsCommandes.get(enu.nextElement());
				if(maxDelai<n[5]){
					maxDelai = n[5];
				}
				coutTotal += n[6];
				i++;
			}
		}
		
	    //Ajoût du délai maximum à la date courante
		Calendar deliveryDate = Calendar.getInstance();
		deliveryDate.add(Calendar.DATE, maxDelai);
		dateLivraison = deliveryDate.getTime();
		
		//Construction du résultat
		jsoRes.put("dateLivraison", maxDelai);
		jsoRes.put("cout", coutTotal);
		
		return jsoRes;
	}
	
	/**
	 * Le but de cette fonction est de renvoyer un JSONObject ayant pour structure :
	 * Id : numServerLoc
	 * Value : JSONArray de JSONObject
	 * 			 {Id : idProduit
	 *			  Value : qte}
	 */
	public JSONObject trans_listCommand (Hashtable<Integer, Integer[]> listCommande)
	{
		System.out.println("########### ( 152 ) Central trans_ListCommand");
		JSONObject jsoListCommand = new JSONObject();
		try 
		{
			//Construction des JSONObject pour chaque site
			String idPrdt;
			JSONObject jsoPrdt1 = new JSONObject();
			JSONObject jsoPrdt2 = new JSONObject();
			JSONObject jsoPrdt3 = new JSONObject();
			JSONObject jsoPrdt4 = new JSONObject();
			JSONObject jsoPrdt5 = new JSONObject();
			
			JSONArray jsaServ1 = new JSONArray();
			JSONArray jsaServ2 = new JSONArray();
			JSONArray jsaServ3 = new JSONArray();
			JSONArray jsaServ4 = new JSONArray();
			JSONArray jsaServ5 = new JSONArray();
			
			if(listCommande.size()!=0){
				Enumeration<Integer> enu=listCommande.keys();
				Integer[] n = new Integer[7];
				while(enu.hasMoreElements()){
					idPrdt = enu.nextElement().toString();
					n = (Integer[]) listCommande.get(idPrdt);
					if(!n[0].equals(null)&&!n[0].equals(0)){
						jsoPrdt1.put(idPrdt, n[0]);
						jsaServ1.put(jsoPrdt1);
					}
					if(!n[1].equals(null)&&!n[1].equals(0)){
						jsoPrdt2.put(idPrdt, n[1]);
						jsaServ2.put(jsoPrdt2);
					}
					if(!n[2].equals(null)&&!n[2].equals(0)){
						jsoPrdt3.put(idPrdt, n[2]);
						jsaServ3.put(jsoPrdt3);
					}
					if(!n[3].equals(null)&&!n[3].equals(0)){
						jsoPrdt4.put(idPrdt, n[3]);
						jsaServ4.put(jsoPrdt4);
					}
					if(!n[4].equals(null)&&!n[4].equals(0)){
						jsoPrdt5.put(idPrdt, n[4]);
						jsaServ5.put(jsoPrdt5);
					}
				}
				jsoListCommand.put("1",jsaServ1);
				jsoListCommand.put("2",jsaServ2);
				jsoListCommand.put("3",jsaServ3);
				jsoListCommand.put("4",jsaServ4);
				jsoListCommand.put("5",jsaServ5);
			}
		} 
		catch (JSONException e){
			e.printStackTrace();
		}
		return jsoListCommand;
	}
	
	public void connexion (String inetAddresses, int port) throws UnknownHostException, IOException
	{
		System.out.println("########### ( 212 ) Central connexion");
		//Chargement des variables en vu d'une communication
		//Ouverture du socket
		skt = new Socket(inetAddresses, port);
		
		//Mise en buffer du stream émis par le socket
		in = new BufferedReader(new InputStreamReader(skt.getInputStream()));
		
		//Préparation de l'émetteur vers le socket client
		out = new PrintWriter(skt.getOutputStream(), true);
	}

	public JSONObject envoiMessageVerifQte (String inetAddress, int port, JSONObject prdt) throws IOException, JSONException
	{
		System.out.println("########### ( 226 ) Central envoiMessageVerifQte");
		//Envoi d'un message au client : fonction attendant une quantité de produit
		//Connexion au client inscrit en paramètre
		connexion(inetAddress, port);
		
		//Envoie d'un Id produit
		out.println(prdt);
		
		//Reception du message de la part du socket
		return receptionMessage();
	}

	/**
	 * Fonction interrogeant les différents sites sur UN produit
	 * Renvoi un tableau d'entier 'prdtCommande[]' contenant la quantité de produit par site
	 * prdtCommande[0...4] contient la quantité de produit demandée aux sites 0...4
	 * prdtCommande[5] contient le nombre de jour estimé pour la livraison totale effective à partir de maintenant.
	 */
	private Integer[] interParProduit (int id, int qte, int numServerLoc) 
		throws 	UnknownHostException, 
				IOException, 
				JSONException
	{	
		System.out.println("########### ( 249 ) Central interParProduit");
		//Initialisation des variables de traitement
		Integer prdtCommande[] = new Integer[7];
		Integer qteATraite = 0;
		Integer qteATraiteT = 0;
		Integer dateLivraison;
		JSONObject prdt = new JSONObject(); //Identifiant produit + quantité
		JSONObject prdtTraite = new JSONObject();
		Integer resQte;
		
		dateLivraison = 0;
		prdt.put("message", "book");
		prdt.put("productId", id);
		prdt.put("wantedQty", qte);
		
		//Initialisation du tableau à 0
		for(int i =0; i<prdtCommande.length; i++){
			prdtCommande[i]=0;
		}
		
		//Vérification présence produit dans le centre dédié
		switch (numServerLoc)
		{
			case 0 : prdtTraite = envoiMessageVerifQte(ipAtt0, portAtt0, prdt);
				break;
			case 1 : prdtTraite = envoiMessageVerifQte(ipAtt1, portAtt1, prdt);
				break;
			case 2 : prdtTraite = envoiMessageVerifQte(ipAtt2, portAtt2, prdt);
				break;
			case 3 : prdtTraite = envoiMessageVerifQte(ipAtt3, portAtt3, prdt);
				break;
			case 4 : prdtTraite = envoiMessageVerifQte(ipAtt4, portAtt4, prdt);
				break;
		}
		
		//Comparaison entre les quantités demandées et les quantités disponibles dans le centre dédié
		resQte = prdtTraite.getInt("availableQty");
		if (resQte>qte){
			qteATraiteT = qte;
		}else{
			qteATraiteT = resQte;
		}
		
		//Retenu du nombre de produit contenu
		prdtCommande[numServerLoc] = qteATraiteT;
		
		/**
		 * Si la quantité voulue n'est pas disponible dans le centre dédié
		 *Alors répartir la charge en fonction de l'éloignement
		 *( 
		 * si le centre dédié est le 2
		 * si ce centre n'a pas la ressource en quantité suffisante 
		 * alors interrogation de la plateforme de la plateforme 3 puis 1, puis 4, puis 0.
		 *)
		 */
		int iPos = numServerLoc;
		int iNeg = numServerLoc;
		
		qteATraite = qte - qteATraiteT;
		
		while(qteATraite>0 && (iPos<=4 || iNeg >=0));
		{
			if(iPos<=4 && (qteATraite)>0)
			{
				//Changement de site
				iPos++;
				
				qteATraite = qte-resQte;
				switch (iPos)
				{
					case 0 : prdtTraite = envoiMessageVerifQte(ipAtt0, portAtt0, prdt);
						break;
					case 1 : prdtTraite = envoiMessageVerifQte(ipAtt1, portAtt1, prdt);
						break;
					case 2 : prdtTraite = envoiMessageVerifQte(ipAtt2, portAtt2, prdt);
						break;
					case 3 : prdtTraite = envoiMessageVerifQte(ipAtt3, portAtt3, prdt);
						break;
					case 4 : prdtTraite = envoiMessageVerifQte(ipAtt4, portAtt4, prdt);
						break;
				}
				//Réception du message
				prdtTraite = receptionMessage();
				
				//Comparaison avec la quantité restant à traiter
				resQte = prdtTraite.getInt("qte");
				if (resQte>qteATraite)
				{
					qteATraiteT = qteATraite;
				}
				else
				{
					qteATraiteT = resQte;
				}
				
				//Insertion de la quantité de produit prélevée à l'indice du site traité
				prdtCommande[iPos] = qteATraiteT;
				qteATraite = qteATraite - qteATraiteT;
			}
			if(iNeg>=0 && (qteATraite)>0)
			{
				iNeg--;
				qteATraite = qte-resQte;
				switch (iNeg)
				{
					case 0 : prdtTraite = envoiMessageVerifQte(ipAtt0, portAtt0, prdt);
						break;
					case 1 : prdtTraite = envoiMessageVerifQte(ipAtt1, portAtt1, prdt);
						break;
					case 2 : prdtTraite = envoiMessageVerifQte(ipAtt2, portAtt2, prdt);
						break;
					case 3 : prdtTraite = envoiMessageVerifQte(ipAtt3, portAtt3, prdt);
						break;
					case 4 : prdtTraite = envoiMessageVerifQte(ipAtt4, portAtt4, prdt);
						break;
				}
				prdtTraite = receptionMessage();
				resQte = prdtTraite.getInt("qte");
				if (resQte>qteATraite){
					qteATraiteT = qteATraite;
				}
				else{
					qteATraiteT = resQte;
				}
				prdtCommande[iNeg] = qteATraiteT;
				qteATraite = qteATraite - qteATraiteT;				
			}
			//Nombre de jour de livraison +1
			dateLivraison++;
		}
		
		//Insertion du nombre de jour à l'indice 5
		prdtCommande[5] = dateLivraison;
		prdtCommande[6] = 0;
		
		//Renvoi du tableau
		return prdtCommande;
	}
	
	public JSONObject receptionMessage() throws IOException, JSONException
	{
		System.out.println("########### ( 390 ) Central receptionMessage");
		//Réception du message
		while (!in.ready());
		String line = in.readLine();
		JSONObject prdt = new JSONObject(line);
		System.out.println("########### ( Central 395 )prdt "+prdt);
		return(prdt);
	}

	public void quit ()
	{
		System.out.println("########### ( 400 ) Central quit");
		try {
			in.close();
			skt.close();
		}catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public boolean identification (String login, String password)
	{
		System.out.println("########### ( 411 ) Central identification");
		return false;		
	}
}